//import AudioTool from "./AudioTool";

import AudioTool from "./AudioTool";

const { ccclass, property } = cc._decorator;

/**
 * 基础api：设置（存储）数据
 * @param {*} key 键名
 * @param {*} value 值
 */
let setData = (key, value) => {
    try {
        let data = value && JSON.stringify(value);
        cc.sys.localStorage.setItem(key, data);
    } catch (e) {
        console.error(key, "save Local Storage fail");
    }
}

/**
 * 基础api：获取数据  
 * @param {*} key 键名
 * @param {*} defaultValue 默认值
 */
let getData = (key, defaultValue) => {
    try {
        let tmp = cc.sys.localStorage.getItem(key);
        if (!tmp && defaultValue != undefined && defaultValue != null && !isNaN(defaultValue)) {
            setData(key, defaultValue);
        }

        return tmp ? JSON.parse(tmp) : defaultValue;
    } catch (e) {
        return defaultValue;
    }
}

/**本地存储的数据 */
let localData_ = {}

@ccclass
export default class Utils {

    protected static _instance: Utils = null;
    public static get Instance(): Utils {
        if (Utils._instance == null) {
            Utils._instance = new Utils();
        }
        return Utils._instance;
    }
    /**
     * 随机一个范围 min~max 的整数 
     * @param {*} min min为一个整数或者为一个2元素的数组
     * @param {*} max max为整数或者没有
     */
    randomInt(min, max?) {
        if (min == max) return min;
        if (max === undefined) {
            max = min[1];
            min = min[0];
        }
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    //加载resources下文件
    loadRes(url, type, completeCallback?, failCallback?, progressCallback?) {
        if (!url) {
            console.error("url为空！！");
            return;
        }
        let extname = cc.path.extname(url);
        if (extname) {
            // strip extname
            url = url.slice(0, - extname.length);
        }
        cc.resources.load(url, type, progressCallback, (err, asset: cc.Asset) => {
            if (err) {
                console.error("加载失败", url, "\n", err);
                if (failCallback) failCallback();
                return;
            }
            if (completeCallback) completeCallback(asset);
        });
    }

    //加载bagBundle下文件
    loadBundle(url, type, completeCallback?, failCallback?, progressCallback?) {
        if (!url) {
            console.error("url为空！！");
            return;
        }
        let extname = cc.path.extname(url);
        if (extname) {
            // strip extname
            url = url.slice(0, - extname.length);
        }
        cc.assetManager.loadBundle('bag', (err, bundle) => {
            if (err) {
                console.error("分包加载失败", url, "\n", err);
                if (failCallback) failCallback();
                return;
            }
            bundle.load(url, type, progressCallback, (err, asset: cc.Asset) => {
                if (err) {
                    console.error("加载失败", url, "\n", err);
                    if (failCallback) failCallback();
                    return;
                }
                if (completeCallback) completeCallback(asset);
            });
        });
    }

    poLoadBundle(completeCallback?) {
        cc.assetManager.loadBundle('bag', (err, bundle) => {
            if (err) {
                console.error("分包预加载失败", "\n", err);
                return;
            }
            if (completeCallback) completeCallback();
        });
    }

    isValidNode(node) {
        return node && node.isValid;
    }

    /**
     * 注册按钮事件
     * @param {*} node 注册节点名
     * @param {*} handlerName 函数名
     * @param {*} socpe 组件
     * @param {*} EventData 事件传的参数
     * @param {*} buttonParam （可选）按钮属性列表，
     * 必须和按钮组件属性名字一样或者自定义属性
     * 例如：
     *  {
            transition: cc.Button.Transition.SCALE,
            duration: 0.1,
            zoomScale: 1.1,
        }
     */
    registerBtnEvent(node: cc.Node, handlerName, socpe, eventData = "", buttonParam = {}) {
        if (!this.isValidNode(node)) {
            return;
        }
        if (handlerName) {
            handlerName = handlerName["name"] ? handlerName["name"] : handlerName;
        }

        /**传入匿名函数的情况, 相当于动态在类增加一个方法 */
        if (typeof (handlerName) == "function") {
            let fnName = "__BtnClick__" + this.randomKey(16);
            socpe[fnName] = handlerName;
            handlerName = fnName;
        }

        let button = node.getComponent(cc.Button);
        if (!button) {
            button = this.addComponent(node, cc.Button);
            if (button) button.transition = cc.Button.Transition.SCALE;
        }
        if (button && !button.clickEvents[0]) {
            let eventHandler = new cc.Component.EventHandler();
            eventHandler.target = socpe.node;
            eventHandler.component = cc.js.getClassName(socpe);
            eventHandler.handler = handlerName;
            eventHandler.customEventData = eventData;
            button.clickEvents[0] = eventHandler;
            for (const key in buttonParam) {
                if (buttonParam && buttonParam.hasOwnProperty(key)) {
                    button[key] = buttonParam[key];
                }
            }
            node.on("click", () => {
                AudioTool.Instance.playEffect("btn_click");
            });
        }
    }

    addComponent(node, component) {
        if (!this.isValidNode(node)) {
            console.error("addComponent error : node is invalid1");
            return;
        }
        if (!component) {
            console.error("addComponent error : param is invalid2");
            return;
        }
        let exists = node.getComponent(component);
        if (exists) {
            return exists;
        }
        let com = null;
        com = node.addComponent(component);
        if (!com) {
            console.error("addComponent error : cant not add component " + node.name + " " + component);
        }
        return com;
    }

    /**
    * 产生随机字母数字组合
    * @param {*} len 字符串长度
    */
    randomKey(len) {
        let arr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
        let str = "";
        let length = arr.length;
        for (let i = 0; i < len; i++) {
            let pos = this.randomInt(0, length - 1);
            str += arr[pos];
        }
        return str;
    }

    setLabelString(node, text, atOnce = true) {
        if (!this.isValidNode(node)) {
            return;
        }
        let label = node.getComponent(cc.Label);
        if (this.isValidNode(label) && label.string != text + "") {
            label.string = text + "";
            if (atOnce) label._forceUpdateRenderData(true);
        }
    }

    isValid = function (value) {
        return !(value == undefined || value == null || (typeof (value) == "number" && isNaN(value)));
    }

    /**
     * 设置纹理
     * @param {*} node 更改的节点
     * @param {*} name 纹理名字
     * @param {*} atlasName 纹理所在的图集名字
     */
    setSpriteFrame(node, name, atlasName?, cb?) {
        //打印加载的纹理图集 
        if (!this.isValid(node)) {
            console.error("SpriteAtlas: setSpriteFrame error, node is invalid");
            return;
        }
        if (!atlasName) {
            this.loadRes(name, cc.SpriteFrame, (res) => {
                this._setSpriteFrame(node, res, name, atlasName);
                if (cb) cb();
            });
            return;
        }
        this.loadRes(atlasName, cc.SpriteAtlas, (res) => {
            this._setAtlaSpriteFrame(res, node, name, atlasName);
            if (cb) cb();
        });
    }

    /**设置远程图片 */
    loadImg(url: string, node: cc.Node, cb?) {
        if (!this.isValid(node) || !this.isValid(url)) return;
        let newUrl = url.slice(-4) == ".jpg" || url.slice(-4) == ".png" ? url : url + "?aaa=aa.jpg";
        cc.assetManager.loadRemote(newUrl, (err, texture: any) => {
            console.log(url);
            if (err) {
                console.error(err);
                return;
            }
            if (!this.isValid(node)) {
                if (cb) cb();
                return;
            }
            let sprite = node.getComponent(cc.Sprite);
            if (!sprite) node.addComponent(cc.Sprite);
            if (!texture) {
                if (cb) cb();
                return;
            }
            sprite.spriteFrame = new cc.SpriteFrame(texture);
            let scale1 = 192 / node.width;
            let scale2 = 241 / node.width;
            node.scale = scale1 > scale2 ? scale2 : scale1;
            if (cb) cb(node);
        });
    }

    //设置图片
    _setAtlaSpriteFrame(res, node, name, atlasName?) {
        let frame = res.getSpriteFrame(name);
        this._setSpriteFrame(node, frame, name, atlasName);
    }

    //设置图片
    _setSpriteFrame(node, res, name?, atlasName?) {
        let frame = res;
        if (!this.isValid(res)) {
            console.error(atlasName + ":" + name + "  纹理不存在");
            return;
        }
        if (!this.isValid(node)) {
            return;
        }
        let sprite = node.getComponent(cc.Sprite);
        if (!sprite) node.addComponent(cc.Sprite);
        if (!sprite || sprite.spriteFrame == frame || !this.isValid(frame)) {
            return;
        }
        sprite.spriteFrame = frame;
    }

    creatPanel(panelName: string, cb?, data?, parent?: cc.Node) {
        let success = (prefab) => {
            let scene = cc.find("ui", cc.find("Canvas"));
            let panel: cc.Node = this.createNode(prefab);
            let script = this.getScript(panel);
            if (panel) {
                try {
                    if (script && script["setData"]) {
                        script.setData(data);
                    }
                } catch (e) {
                    console.error("setData", panelName, e)
                }
                panel.parent = parent ? parent : scene;
                panel.addComponent(cc.BlockInputEvents);
                if (cb) cb(panel);
            }
        }
        if (panelName == "startPanel") {
            this.loadRes("panel/" + panelName, cc.Prefab, success, cb);
        }
        else {
            this.loadBundle("panel/" + panelName, cc.Prefab, success, cb)
        }
    }

    getScript(node: cc.Node) {
        if (!node) return;
        //@ts-ignore
        let arr = node._components;
        for (let i = 0; i < arr.length; i++) {
            const element = arr[i];
            if (element && element.hasOwnProperty("_super")) {
                return arr[i];
            }
        }
        return null;
    }

    /**
     * 创建一个节点
     * @param {*} object cc.Prefab|cc.Node
     */
    createNode(object) {
        if (!this.isValidNode(object)) {
            if (cc.debug) console.error("预制体不存在!");
            return null;
        }
        let node = cc.instantiate(object);
        if (!this.isValidNode(node)) {
            if (cc.debug) console.error("创建节点失败!");
            return null;
        }
        return node;
    }

    /**获取当前时间戳：秒 */
    getCurTime() {
        return Math.ceil(Date.now() / 1000);
    }

    /**
     * 当前用户，设置数据
     * @param {*} key 键名
     * @param {*} value 值
     */
    setStorageByUid(uid, key, value) {
        key += "_" + uid;
        localData_[key] = value;
        setData(key, value);
    }

    /**
     * 当前用户，获取数据
     * @param {*} key 键名
     * @param {*} defaultValue 值
     */
    getStorageByUid(uid, key, defaultValue) {
        let temp;
        key += "_" + uid;
        if (localData_.hasOwnProperty(key)) {
            return this.isValid(localData_[key]) ? localData_[key] : defaultValue;
        } else {
            temp = getData(key, defaultValue);
            localData_[key] = temp;
            return temp;
        }
    }

    clearStorageByUid(uid, key) {
        key += "_" + uid;
        delete localData_[key];
        cc.sys.localStorage.removeItem(key);
    }
}
